<template>
  <el-tree
    ref="treeRef"
    :data="treeDataVo"
    :props="{
      label: (data, node) => data.props.label,
    }"
    draggable
    show-checkbox
    check-strictly
    node-key="id"
    :allow-drop="collapse"
    :default-checked-keys="getDefaultKeys(treeDataVo)"
    @node-drag-start="dragStart"
    @node-drag-end="dragEnd"
    @check="clickDeal"
  >
    <template #default="{ node, data }">
      <div
        class="flex items-center cursor-move wfull hfull justify-between"
        @mouseenter="node.showLeft = true"
        @mouseleave="node.showLeft = false"
      >
        <div class="left flex items-center">
          <svg-icon name="drag" :size="16"></svg-icon>
          <span>{{ node.label }}</span>
        </div>
        <div class="right" v-if="!data.parentId && node.showLeft">
          <el-tooltip content="固定在列首" v-if="fixedType != 'left'">
            <svg-icon
              class="mr-2 cursor-pointer"
              name="align-top"
              :size="16"
              @click="fixedTypeChange(data, 'left')"
            ></svg-icon>
          </el-tooltip>
          <el-tooltip content="不固定" v-if="fixedType">
            <svg-icon
              class="mr-2 cursor-pointer"
              name="align-center"
              :size="16"
              @click="fixedTypeChange(data)"
            ></svg-icon>
          </el-tooltip>
          <el-tooltip content="固定在列尾" v-if="fixedType != 'right'">
            <svg-icon
              class="cursor-pointer"
              name="align-bottom"
              :size="16"
              @click="fixedTypeChange(data, 'right')"
            ></svg-icon>
          </el-tooltip>
        </div>
      </div>
    </template>
  </el-tree>
</template>
<script setup lang="ts">
import type Node from "element-plus/es/components/tree/src/model/node";
import type { AllowDropType } from "element-plus/es/components/tree/src/tree.type";
import { type ElTree } from "element-plus";
import {
  ColumnProps,
  _fixedType,
} from "@/components/baseTable/interface/types";
import treeTool from "@/utils/tree";

const emit = defineEmits(["treeDataChange", "fixedTypeChange"]);

interface tProps {
  treeData: ColumnProps[];
  fixedType?: _fixedType;
}

const props = withDefaults(defineProps<tProps>(), {});
const treeDataVo = ref<ColumnProps[]>([...props.treeData]);
const nowCheck = ref<any[]>([]);
const treeRef = ref<InstanceType<typeof ElTree>>();

const collapse = (draggingNode: Node, dropNode: Node, type: AllowDropType) => {
  if (draggingNode.level === dropNode.level) {
    if (draggingNode.parent.id === dropNode.parent.id) {
      return type === "prev" || type === "next";
    } else {
      return false;
    }
  } else {
    // 不同级进行处理
    return false;
  }
};

//获取所有的keys
const getAllKeys = (columnTree: ColumnProps[]) => {
  const checksKeys = treeTool.toList(columnTree).map((item: any) => item.id);
  return checksKeys;
};

//获取初始化的时候默认选中的keys
const getDefaultKeys = (columnTree: ColumnProps[]) => {
  const checksKeys = treeTool
    .toList(columnTree)
    .filter((item) => {
      return item.props._isShow;
    })
    .map((item: any) => item.id);
  return checksKeys;
};

const clickDeal = (currentObj: any, treeStatus: any) => {
  clickCheck(currentObj, treeStatus, treeRef.value);
  checkChange();
};

/**
 * 树形菜单复选框父子节点不关联实现父子节点联动回显
 *
 * @see selectedParent - 处理父节点为选中
 * @see uniteChildSame - 处理子节点为相同的勾选状态
 * @see removeParent   - 子节点全没选中取消父级的选中状态
 *
 * @param {Object} currentObj - 当前勾选节点的对象
 * @param {Object} treeStatus - 树目前的选中状态对象
 * @param {Object} ref - this.$refs.xxx
 **/
const clickCheck = (currentObj: any, treeStatus: any, ref: any) => {
  // 用于：父子节点严格互不关联时，父节点勾选变化时通知子节点同步变化，实现单向关联。
  let selected = treeStatus.checkedKeys.indexOf(currentObj.id); // -1未选中

  // 选中
  if (selected !== -1) {
    // 子节点只要被选中父节点就被选中
    selectedParent(currentObj, ref);
    // 统一处理子节点为相同的勾选状态
    uniteChildSame(currentObj, true, ref);
  } else {
    // 取消子节点的选中状态触发
    if (currentObj.parentId !== -1) {
      removeParent(currentObj, ref);
    }
    // 未选中 处理子节点全部未选中
    if (currentObj.children && currentObj.children.length !== 0) {
      uniteChildSame(currentObj, false, ref);
    }
  }
};

/**   统一处理子节点为相同的勾选状态  **/
const uniteChildSame = (treeList: any, isSelected: any, ref: any) => {
  let treeListData = treeList.children || [];
  let len = treeListData.length;

  ref.setChecked(treeList.id, isSelected);

  for (let i = 0; i < len; i++) {
    uniteChildSame(treeListData[i], isSelected, ref);
  }
};

/**    统一处理父节点为选中    **/
const selectedParent = (currentObj: any, ref: any): any => {
  let currentNode = ref.getNode(currentObj);
  if (currentNode.parent.key !== undefined) {
    ref.setChecked(currentNode.parent, true);
    return selectedParent(currentNode.parent, ref);
  }
};

/**    子节点全没选中取消父级的选中状态   **/
const removeParent = (currentObj: any, ref: any): any => {
  let a = 0;
  let b = 0;
  let currentNode = ref.getNode(currentObj);
  if (currentNode.parent !== null) {
    if (currentNode.parent.key !== undefined) {
      ref.setChecked(currentNode.parent, true); //根节点
      removeParent(currentNode.parent, ref); //递归判断子节点
    }
  }

  //不为0表示为父节点
  if (currentNode.childNodes.length !== 0) {
    //循环判断父节点下的子节点
    for (let i = 0; i < currentNode.childNodes.length; i++) {
      //判断父节点下的子节点是否全为false
      if (currentNode.childNodes[i].checked === false) {
        ++a;

        //a === currentNode.childNodes.length 表明子节点全为false
        if (a === currentNode.childNodes.length) {
          //等于 undefined 跳过,不等于继续执行
          if (currentNode.childNodes[i].parent.key !== undefined) {
            ref.setChecked(currentNode.childNodes[i].parent, false); //父元素设置为false
            //循环上级父节点下的子节点
            for (let i = 0; i < currentNode.parent.childNodes.length; i++) {
              //判断父节点下的子节点是否全为false
              if (currentNode.parent.childNodes[i].checked === false) {
                ++b;

                //b === currentNode.parent.childNodes.length 表明子节点全为false
                if (b === currentNode.parent.childNodes.length) {
                  ref.setChecked(currentNode.parent.key, false); //父元素设置为false
                  return removeParent(currentNode.parent, ref); //继续递归循环判断
                }
              }
            }
          }
        }
      }
    }
  }
};

//拖拽开始
const dragStart = () => {
  nowCheck.value = treeRef.value!.getCheckedKeys();
};

//拖拽结束
const dragEnd = () => {
  nextTick(() => {
    treeRef.value!.setCheckedKeys(nowCheck.value);
    emit("treeDataChange");
  });
};

const checkChange = (sendEmit = true) => {
  const nowCheckKeys = treeRef.value!.getCheckedKeys();
  treeTool.forEach(treeDataVo.value, (item) => {
    if (nowCheckKeys.includes(item.id)) {
      item.props._isShow = true;
    } else {
      item.props._isShow = false;
    }
  });
  sendEmit && emit("treeDataChange", props.fixedType);
};

//全部选择
const checkAllTrue = () => {
  treeRef.value!.setCheckedKeys(getAllKeys(treeDataVo.value));
  checkChange(false);
};
//全部取消选中
const checkAllFalse = () => {
  treeRef.value!.setCheckedKeys([]);
  checkChange(false);
};
//获取数据
const getTreeData = () => {
  return treeDataVo.value;
};
//点击到列首
const fixedTypeChange = (item: ColumnProps, target?: _fixedType) => {
  emit("fixedTypeChange", item, target);
};

defineExpose({
  checkAllTrue,
  checkAllFalse,
  getTreeData,
});
</script>

<style scoped lang="scss"></style>
